Skip to content

feat(terminal): unify xterm client and harden transport - #5038

Open
ErickCReis wants to merge 11 commits into
Dokploy:canaryfrom
ErickCReis:feature/improve-terminal-ux
Open

ErickCReis wants to merge 11 commits into
Dokploy:canaryfrom
ErickCReis:feature/improve-terminal-ux

Conversation

@ErickCReis

@ErickCReis ErickCReis commented Aug 11, 2026 •

Copy link
Copy Markdown

What changed

This PR builds on #5104. That PR synchronizes browser dimensions with Docker and SSH PTYs and fixes the overwrite reported in #5092. This PR keeps that behavior and adds the remaining terminal transport, lifecycle, and client improvements.

  • Moves the server and Docker terminals to one shared xterm client.
  • Preserves terminal input byte for byte through WebSocket and node-pty or SSH. This covers X10 mouse reports and bytes outside ASCII.
  • Sends terminal input as binary frames and resize controls as validated text JSON frames. Other text frames remain terminal input for older clients.
  • Uses the same 500-column and 200-row bounds in the browser and server, then coalesces and deduplicates resize messages.
  • Stops PTY writes, resizes, and cleanup after process exit. Resize and kill failures no longer crash the WebSocket handler.
  • Removes WebSocket output listeners before disposing xterm, so queued output cannot reach a disposed terminal.
  • Defers xterm creation by one animation frame so React StrictMode can cancel its throwaway development mount before fit() runs.
  • Adds theme-aware colors, search, Unicode 11 width handling, link detection, and terminal-safe keyboard shortcuts.
  • Measures Docker log cell width from the rendered font and updates the log PTY when the viewport changes.
  • Keeps normal browser and OS paste, including bracketed multiline Unicode paste.
  • Replaces unrestricted OSC 52 clipboard handling with bounded, write-only support. A remote shell can set valid clipboard text but cannot read the browser clipboard.

Why

#5104 fixes the visible PTY-size desynchronization, but its transport still decodes binary WebSocket input as UTF-8 text. Mouse reports and non-ASCII bytes can change before they reach the PTY. Its resize controls also share text frames with stdin.

This PR gives stdin and resize controls distinct frame types. It also centralizes behavior that was duplicated between the server and Docker terminal clients. Both terminals now use the same resizing, cleanup, theme, search, Unicode, link, keyboard, and clipboard code.

Related work

Validation

The final checks ran with Node 24.4.0 and pnpm 10.22.0 after merging the latest canary and pushing the StrictMode lifecycle fix.

  • corepack pnpm --filter=dokploy exec vitest --config __test__/vitest.config.ts __test__/wss/utils.test.ts __test__/wss/terminal-transport.test.ts --run passed 33 tests.
  • corepack pnpm --filter=dokploy run typecheck passed.
  • corepack pnpm --filter=dokploy run build passed. The build logged the expected missing local dokploy-postgres and deprecated local configuration warnings.
  • Biome passed on the changed xterm client.
  • git diff --check passed.
  • React Doctor reported no finding in the changed xterm client. Its branch-wide scan reported findings in other files, but none came from this lifecycle fix.

Checklist

  • The branch is based on canary and includes the latest changes from it.
  • The contribution follows the Dokploy contribution guide.
  • The terminal behavior was tested in a local instance during development.

Tooling disclosure

This contribution was built and validated with Codex.

Greptile Summary

This PR consolidates server and container terminals around a shared xterm client and hardens terminal transport and lifecycle behavior.

  • Separates binary terminal input from validated text resize controls.
  • Synchronizes bounded PTY dimensions across browser, Docker, and SSH paths.
  • Adds shared terminal search, Unicode, links, themes, keyboard handling, and restricted OSC 52 clipboard writes.
  • Improves PTY, WebSocket, and xterm cleanup behavior.

Confidence Score: 5/5

The PR appears safe to merge because no blocking failure remains in the eligible follow-up review scope.

No blocking failure remains.

Reviews (3): Last reviewed commit: "Merge remote-tracking branch 'origin/can..." | Re-trigger Greptile

Context used:

Follow-up fix

- Share reusable xterm setup across terminal views
- Resize local and remote PTYs with validated dimensions
- Add terminal search, links, Unicode, and clipboard support
- Validate terminal dimensions strictly
- Normalize WebSocket errors safely
- Simplify terminal query and search focus handling
…minal-ux

# Conflicts:
#	apps/dokploy/components/dashboard/docker/logs/docker-logs-id.tsx
#	apps/dokploy/components/dashboard/docker/terminal/docker-terminal.tsx
#	apps/dokploy/components/dashboard/settings/web-server/terminal.tsx
#	apps/dokploy/server/wss/docker-container-terminal.ts
#	apps/dokploy/server/wss/terminal.ts
@ErickCReis
ErickCReis marked this pull request as ready for review August 18, 2026 00:23
@dosubot dosubot Bot added the size:XXL This PR changes 1000+ lines, ignoring generated files. label Aug 18, 2026
@ErickCReis ErickCReis changed the title feat(terminal): improve resizing and transport safety feat(terminal): unify xterm client and harden transport Aug 18, 2026
Destroy pending SSH clients when the terminal WebSocket closes and reject channels created after disconnect.
@ErickCReis
ErickCReis force-pushed the feature/improve-terminal-ux branch from 4fbd00a to 959790f Compare August 29, 2026 14:23

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL This PR changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Remote terminal leaks SSH/PTY sessions when WebSocket closes during SSH handshake bug when using terminal

1 participant